#pragma once

#include "BottomLevelAccelerationStructure.h"

class TopLevelAccelerationStructure : public AccelerationStructure
{

	struct BuilderDetails {

		VkBuildAccelerationStructureFlagsKHR flags;
		VkBool32 arrayOfPointers;
		VkGeometryFlagsKHR geometryFlags;
		std::vector<RefCountPtr<BottomLevelAccelerationStructure>> bottomLevelAccelerationStructures;

		BuilderDetails()
		{
			flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;

			arrayOfPointers = VK_FALSE;
			geometryFlags = VK_GEOMETRY_OPAQUE_BIT_KHR;
		}
	};

public:

	class Builder : public BuilderBase<BuilderDetails> {
		friend struct BuilderDetails;
	public:
		Builder() noexcept;
		Builder(Builder const& rhs) noexcept;
		Builder(Builder&& rhs) noexcept;
		~Builder() noexcept;
		Builder& operator=(Builder const& rhs) noexcept;
		Builder& operator=(Builder&& rhs) noexcept;

		Builder& SetFlags(VkBuildAccelerationStructureFlagsKHR flags) noexcept;
		Builder& SetArrayOfPointers(VkBool32 arrayOfPointers) noexcept;
		Builder& SetGeometryFlags(VkGeometryFlagsKHR geometryFlags) noexcept;
		Builder& AddBlas(RefCountPtr<BottomLevelAccelerationStructure> bottomLevelAccelerationStructure) noexcept;

		RefCountPtr<TopLevelAccelerationStructure> Build();
		RefCountPtr<TopLevelAccelerationStructure> Build(RenderProcess* process, const std::string& name);

	private:
		friend class TopLevelAccelerationStructure;
	};

	TopLevelAccelerationStructure(BuilderDetails& builderDetails);

	virtual void ReleaseResource() override;

	void UpdateTlas();

protected:

	void CompactionAndBuildBlas();

	void CreateInstanceGeometries();

protected:

	VkAccelerationStructureGeometryKHR mAccelerationStructureGeometry;

	std::vector<RefCountPtr<BottomLevelAccelerationStructure>> mBottomLevelAccelerationStructures;

	VkBuffer mInstanceBuffer;

	VkDeviceMemory mInstanceMemory;
};